package com.security.it.authentication.common;

import com.security.it.authentication.exception.ValidateCodeException;
import com.security.it.core.constants.SecurityConstants;
import com.security.it.core.enums.ValidateCodeType;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.context.request.ServletWebRequest;

import javax.annotation.Resource;
import java.util.List;

/**
 * 抽象处理器
 */
public abstract class AbstractValidateCodeProcessor<T> implements ValidateCodeProcessor {

    /**
     * session工具类
     */
    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    /**
     * 收集所有{@link ValidateCodeGenerator} 接口的实现
     */
    @Resource
    private List<ValidateCodeGenerator> validateCodeGenerators;

    @Override
    public void create(ServletWebRequest request, ValidateCodeType type) throws Exception {
        // 生成验证码
        T validateCode = generate(request, type);
        // 保存验证码
        save(request, validateCode, type);
        // 发送
        send(request, validateCode);
    }

    private void save(ServletWebRequest request, T validateCode, ValidateCodeType type) {
        sessionStrategy.setAttribute(request, String.format(SecurityConstants.SESSION_KEY_PREFIX, type.getCode().toUpperCase()), validateCode);
    }

    /**
     * 发送验证码
     *
     * @param request
     * @param validateCode
     */
    protected abstract void send(ServletWebRequest request, T validateCode) throws Exception;

    /**
     * 校验验证码
     *
     * @param request
     * @throws Exception
     */
    public abstract void validate(ServletWebRequest request) throws Exception;

    /**
     * 对应匹配的处理器
     * @param type
     */
    protected abstract boolean accept(ValidateCodeType type);

    /**
     * 生成验证码
     *
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    private T generate(ServletWebRequest request, ValidateCodeType type) {
        ValidateCodeGenerator generator = getGenerator(type);
        return (T) generator.generate(request);
    }

    /**
     * 选择验证码生成器
     */
    private ValidateCodeGenerator getGenerator(ValidateCodeType type) {
        for (ValidateCodeGenerator generator : validateCodeGenerators) {
            if (generator.accept(type)) {
                return generator;
            }
        }
        throw new ValidateCodeException("not Bean!");
    }
}
